Last updated: 2025-05-28
Checks: 6 1
Knit directory: /mnt/central_nas/projects/type1_diabetes/nathan/BlockCourse/2024_BlockCourse/T1D_analysis/
This reproducible R Markdown analysis was created with workflowr (version 1.7.1). The Checks tab describes the reproducibility checks that were applied when the results were created. The Past versions tab lists the development history.
The R Markdown file has unstaged changes. To know which version of the R Markdown file created these results, you’ll want to first commit it to the Git repo. If you’re still working on the analysis, you can ignore this warning. When you’re finished, you can run wflow_publish to commit the R Markdown file and build the HTML.
Great job! The global environment was empty. Objects defined in the global environment can affect the analysis in your R Markdown file in unknown ways. For reproduciblity it’s best to always run the code in an empty environment.
The command set.seed(12345) was run prior to running the code in the R Markdown file. Setting a seed ensures that any results that rely on randomness, e.g. subsampling or permutations, are reproducible.
Great job! Recording the operating system, R version, and package versions is critical for reproducibility.
Nice! There were no cached chunks for this analysis, so you can be confident that you successfully produced the results during this run.
Great job! Using relative paths to the files within your workflowr project makes it easier to run your code on other machines.
Great! You are using Git for version control. Tracking code development and connecting the code version to the results is critical for reproducibility.
The results in this page were generated with repository version 955a62a. See the Past versions tab to see a history of the changes made to the R Markdown and HTML files.
Note that you need to be careful to ensure that all relevant files for the analysis have been committed to Git prior to generating the results (you can use wflow_publish or wflow_git_commit). workflowr only checks the R Markdown file, but you know if there are other scripts or data files that it depends on. Below is the status of the Git repository when the results were generated:
Ignored files:
Ignored: T1D_analysis/figure/
Ignored: processing/
Untracked files:
Untracked: T1D_analysis/05_CellCategories_cells_Uncompressed.html
Unstaged changes:
Modified: T1D_analysis/01_ImportData_cells_Compressed.html
Modified: T1D_analysis/02_SpilloverCompensation_cells_Compressed.html
Modified: T1D_analysis/03_TransformCorrect_cells_Compressed.html
Modified: T1D_analysis/04_QualityControl_cells_Compressed.html
Modified: T1D_analysis/05_CellCategories_cells_Compressed.Rmd
Modified: T1D_analysis/05_CellCategories_cells_Uncompressed.Rmd
Note that any generated files, e.g. HTML, png, CSS, etc., are not included in this status report because it is ok for generated content to have uncommitted changes.
These are the previous versions of the repository in which changes were made to the R Markdown (T1D_analysis/05_CellCategories_cells_Compressed.Rmd) and HTML (T1D_analysis/05_CellCategories_cells_Compressed.html) files. If you’ve configured a remote Git repository (see ?wflow_git_remote), click on the hyperlinks in the table below to view the files as they were in that past version.
| File | Version | Author | Date | Message |
|---|---|---|---|---|
| Rmd | 955a62a | nathansteenbuck | 2025-05-28 | full update 2025 annotation |
| Rmd | 35c060e | nathansteenbuck | 2025-05-27 | minor updates pipeline |
| Rmd | e21a12b | nathansteenbuck | 2024-11-20 | edits scripts |
| Rmd | f9ec97c | nathansteenbuck | 2024-11-20 | adjust descriptions |
| Rmd | 08f607f | nathansteenbuck | 2024-11-19 | update channel decomposition + installation |
| Rmd | 1f3aba7 | nathansteenbuck | 2024-11-12 | T1D_analysis with uncompressed cell type annotation |
| Rmd | d572272 | nathansteenbuck | 2024-11-11 | T1D_analysis v1 |
| Rmd | 801814b | nathansteenbuck | 2024-10-23 | minor edits, paths |
| Rmd | 4c5de28 | nathansteenbuck | 2024-10-23 | First backbone analysis |
Rscript -e “rmarkdown::render(‘2024_BlockCourse/T1D_analysis/05_CellCategories_cells_Compressed.Rmd’)”
In the following scripts, cell types are attributed to all cells in the dataset in an iterative way:
05_CellCategories_cells_Compressed (this script):
06_CellCategories_cells_Compressed:
This is performed by performing PhenoGraph clustering using the Rphenoannoy package.
For cell type annotation we perform unsupervised clustering, and then relate the lineage marker expression of clusters to cell types.
The resulting cell categories, which are used in downstream analyses are stored as colData(spe)$cell_category.
Here, the idea is to use the MINIMAL dataset to generate cell categories that can be used for the T1D dataset.
suppressPackageStartupMessages(c(
library(data.table),
library(dplyr),
library(SpatialExperiment),
library(parallel),
library(purrr),
library(furrr)
))
# Paths
if (!dir.exists(paths$folder_script)) dir.create(paths$folder_script)
plotsave_param$path <- paths$folder_script
plotsave_param_large$path <- paths$folder_script
# Misc settings
today <- gsub("-", "", Sys.Date())
Load the SpatialExperiment (SPE) object saved at the previous step.
fn_spe <- file.path(paths$folder_out, paste0(paths$object_type, "_", paths$panel_type, ".rds"))
spe <- readRDS(fn_spe)
print(spe)
class: SpatialExperiment
dim: 27 139629
metadata(1): spillover_matrix
assays(6): counts compcounts ... scaled fastMNN_case_id
rownames(27): H3 CD44_GCG ... DNA3 PPY
rowData names(10): channel metal ... shortname channel_name
colnames(139629): 6238_Compressed_001_1 6238_Compressed_001_2 ...
6396_Compressed_030_1445 6396_Compressed_030_1446
colData names(30): case_id panel ... HbA1c C_peptide
reducedDimNames(0):
mainExpName: NULL
altExpNames(0):
spatialCoords names(2) : cell_x cell_y
imgData names(1): sample_id
RPhenoannoy can installed with: devtools::install_github("stuchly/Rphenoannoy@8b81e2e7fb0599f45070e2cba1b28ac219b7c472")
suppressPackageStartupMessages(c(
library(ggplot2),
library(scater),
library(scuttle),
library(scran),
library(Rphenoannoy),
library(patchwork),
library(BiocParallel)
))
Select channels (channels_clust), assays (assay_sel) and clustering methods (methods_sel) to use.
methods_sel <- c("Pheno1")
assay_sel <- c("scaled")
names(assay_sel) <- c("scaled")
writeLines(c("Assays:", assay_sel[assay_sel %in% assayNames(spe)],
assay_sel[assay_sel %in% reducedDimNames(spe)]))
Assays:
scaled
dimred_sel <- c("UMAP")
writeLines(c("\nReduced dimensions:", dimred_sel))
Reduced dimensions:
UMAP
channels <- rownames(spe)[!(grepl("DNA|H3", rownames(spe)))]
cat(c("\nChannels:", channels[channels %in% rownames(spe)]))
Channels: CD44_GCG GLUT1 CD99 CD68 MPO SMA CD20_SST AMY CD3e_NKX6_1 CK19 PDX1 SYP CD45RO FOXP3 CD45RA CD8a_INS CA9 IAPP CD4_ProINS CD31 Ecdh PTPRN PCSK2 PPY
cat(c("\nNumber of channels:", length(channels)))
Number of channels: 24
Reduced dimension plots showing marker expression that generated by the previous script can be used to select the most relevant markers for clustering.
In the first step, we just use Cell Category markers for clustering.
channels_clust <- rownames(rowData(spe)[rowData(spe)$clustering == 1, ])
cat(c("\nChannels used for unsupervised clustering:",
channels_clust[channels_clust %in% rownames(spe)]))
Channels used for unsupervised clustering: CD44_GCG GLUT1 CD99 CD68 MPO SMA CD20_SST AMY CD3e_NKX6_1 CK19 PDX1 SYP CD45RO FOXP3 CD45RA CD8a_INS CA9 IAPP CD4_ProINS CD31 Ecdh PTPRN PCSK2 PPY
# Select Channels we will do our Category assignment on.
channels_cat <- c("SYP", "AMY", "CK19",
"CD45RA", "CD45RO", "MPO", "CD68",
"SMA", "CD31",
"CD3e_NKX6_1", "CD4_ProINS", "CD44_GCG", "CD20_SST", "CD8a_INS")
cat(c("\nChannels used for cell category assignment:",
channels_cat[channels_cat %in% rownames(spe)]))
Channels used for cell category assignment: SYP AMY CK19 CD45RA CD45RO MPO CD68 SMA CD31 CD3e_NKX6_1 CD4_ProINS CD44_GCG CD20_SST CD8a_INS
# Extract the metadata (to avoid conflicts when merging the SCEs)
meta <- metadata(spe)
spatial_coords <- spatialCoords(spe)
colpairs <- colPairs(spe)
# Convert to SingleCellExperiment
sce <- as(spe, "SingleCellExperiment")
# sce_cat <- sce[channels_cat, ]
sce_cat <- spe[channels_cat, ]
Unsupervised clustering is performed with the PhenoGraph algorithm. This method works by generating a nearest-neighbor (kNN) graph of phenotpyic similarities followed by Louvain community dectection.
Here, we try the Rphenoannoy implementation. RPhenoannoy implements a parallel Jaccard-coefficient, approximates the kNN and uses Louvain clustering.
clust_method <- c("Pheno1")
cur_assay <- "scaled"
# Number of nearest-neighbors
k <- 30
# Run Phenograph - PhenoGraph for exprs and scaled assay.
clust_name <- paste(clust_method, cur_assay, "cat", sep = "_")
writeLines(c("\n", clust_name))
Pheno1_scaled_cat
if (!clust_name %in% colnames(colData(sce_cat))) {
set.seed(seed)
# Run Rphenograph.
cur_pheno_annoy <- Rphenoannoy::Rphenoannoy(t(assay(sce_cat, cur_assay)), k = k)
cur_pheno <- DataFrame(cur_pheno_annoy[[2]]$membership)
colnames(cur_pheno) <- clust_name
rownames(cur_pheno) <- colnames(assay(sce_cat, cur_assay))
# Add Phenograph clusters to the colData of the SCE object
# Cluster `0` is attributed to non-subsetted cells and not islet cells
colData(sce_cat)[, clust_name] <- cur_pheno
remove(cur_pheno)
}
Run Rphenograph starts:
-Input data of 139629 rows and 14 columns
-k is set to 30
Finding nearest neighbors...DONE ~ 35.958 s
Compute jaccard coefficient between nearest-neighbor sets...
Presorting knn...
presorting DONE ~ 6.923 s
Start jaccard
DONE ~ 0.155 s
Build undirected graph from the weighted links...DONE ~ 2.844 s
Run louvain clustering on the graph ...DONE ~ 82.491 s
Run Rphenograph DONE, totally takes 121.448s.
Return a community class
-Modularity value: 0.8481285
-Number of clusters: 27
suppressPackageStartupMessages(c(
library(heatmaply),
library(htmltools)#,
#library(cytomapper)
))
Subset SCE-CAT object.
set.seed(222)
if (!("subset" %in% names(metadata(sce_cat)))) {
# Cells per case
nb_cells <- 7500
# Subset the SPE object (nb_cells per case)
cell_subset <- tibble(rn = rownames(colData(sce_cat)),
case_id = colData(spe)$case_id) |>
group_by(case_id) |>
sample_n(nb_cells) |>
pull(rn)
# Keep the subset cell ids in SPE metadata
metadata(spe)[["subset"]] <- sort(as.vector(cell_subset))
}
# Subset the SPE object
sce_sub_cat <- sce_cat[channels_cat, metadata(spe)[["subset"]]]
RUN UMAP on reduced category SPE.
# Save as variable and write assays to NULL. Reduces memory overhead for parallelization.
# Add UMAPs to SPE object
dimred_name <- paste("UMAP", cur_assay, "cat", sep = "_")
print(dimred_name)
[1] "UMAP_scaled_cat"
# Run UMAP on a cell subset
if ((!dimred_name %in% reducedDimNames(sce_sub_cat)) && ("UMAP" %in% dimred_sel)) {
# Extract Counts.
if (cur_assay %in% assayNames(spe)) {
counts <- t(assay(sce_sub_cat, cur_assay))
}
# Run UMAP.
umap_model <- uwot::umap(counts, ret_model = TRUE)
# Extract Embedding.
cur_umap <- umap_model$embedding
colnames(cur_umap) <- c("UMAP1", "UMAP2")
rownames(cur_umap) <- rownames(counts)
}
reducedDim(sce_sub_cat, dimred_name) <- cur_umap
cur_method <- "Pheno1"
cur_dimred <- "UMAP"
cur_assay <- "scaled"
cur_dat <- makePerCellDF(sce_sub_cat, use_dimred = TRUE) |>
dplyr::mutate(case_id = factor(case_id, levels = meta$cases),
donor_type = factor(donor_type, levels = meta$stages)) |>
dplyr::arrange(case_id, donor_type) |>
tibble::as_tibble()
dimred_name <- paste(cur_dimred, cur_assay, "cat", sep = "_")
clust_name <- paste(cur_method, cur_assay, "cat", sep = "_")
# Plot all clustersdat, dimred, color_by
p <- plot_dim_red(dat = cur_dat, dimred = dimred_name, color_by = clust_name,
sample = TRUE, size = 0.1, alpha = 1)
print(p)
fn <- paste0(paste(today, "Clusters", clust_name, cur_dimred,
sep = "_"), ".png")
do.call(ggsave, c(list(fn, p), plotsave_param))
name_cur_assay <- "scaled"
clust_name <- paste(cur_method, cur_assay, "cat", sep = "_")
message(clust_name)
Pheno1_scaled_cat
message(name_cur_assay)
scaled
# Summarize the data
hm <- summarize_heatmap(sce_cat,
expr_values = name_cur_assay,
cluster_by = clust_name,
channels = channels_cat)
# Display the heatmap
fn <- paste0(paste(today, "Clusters", clust_name, "Heatmap",
sep = "_"), ".html")
print(fn)
[1] "20250528_Clusters_Pheno1_scaled_cat_Heatmap.html"
heatmaply::heatmaply(
heatmaply::normalize(hm), main = clust_name,
file = file.path(paths$folder_script, fn))
# remove all clusters with less than 10 cells and plot again.
clust_freq <- table(colData(sce_cat)[[clust_name]])
keep_clusts <- names(clust_freq)[clust_freq >= 10]
sce_isl_sub <- sce_cat[, colData(sce_cat)[[clust_name]] %in% keep_clusts]
hm <- summarize_heatmap(sce_isl_sub,
expr_values = name_cur_assay,
cluster_by = clust_name,
channels = channels_cat)
# Display the reduced heatmap -> this improves the visualization.
# Otherwise heatmap is scaled by expression of outliers.
fn <- paste0(paste(today, "Clusters", clust_name, "Heatmap_reduced",
sep = "_"), ".html")
print(fn)
[1] "20250528_Clusters_Pheno1_scaled_cat_Heatmap_reduced.html"
heatmaply::heatmaply(
heatmaply::normalize(hm), main = clust_name,
file = file.path(paths$folder_script, fn))
Put these into the following compartments: Islet, Immune, Exocrine, Stroma, Other.
Here, we use the cytoviewer package to visualize the clusters on the images. Thereby, we can check if the clusters are biologically meaningful and if they indeed correspond to the respective cell types.
Additional information we can use is their spatial localization of cell types, i.e. which cells in the endocrine or exocrine compartment.
viz_clust <- c(1:29) # Select cluster(s) to visualize.
viz_method <- "Pheno1"
viz_assay <- "scaled"
Adjust function.
imgloader <- function(x, image_dir, image_names,
suffix_rem = "", suffix_add = "",
bit_depth = 16, type, ...) {
require(cytomapper)
image_list <- file.path(image_dir, image_names)
# Test if the image list exist
test_exist <- which(!file.exists(image_list))
if (length(test_exist) > 0) {
stop(c("The following images were not found:\n",
paste(image_list[test_exist], collapse = "\n")))
} else {
# Load and scale the images
images <- loadImages(image_list, ...)
# images <- scaleImages(images, (2 ^ bit.depth) - 1)
# Add image names to metadata
mcols(images)$ImageName <- gsub(suffix_rem, "", names(images))
mcols(images)$ImageName <- paste0(mcols(images)$ImageName, suffix_add)
# Add channel names
if (type == "stacks") {
print("Loading image stacks")
channelNames(images) <- rownames(x)
}
return(images)
}
}
spe$Pheno1_scaled_cat <- factor(sce_cat$Pheno1_scaled_cat, levels = 1:29)
if (!is.null(viz_clust)) {
nb_images <- 14
image_extension <- ".tiff"
clust_name <- paste(viz_method, viz_assay, "cat", sep = "_")
# Subset the SCE
sce_viz <- spe[, colData(spe)[[clust_name]] %in% viz_clust]
# Select random image.
set.seed(seed)
image_sub <- sort(sample(
unique(sce_viz$image_fullname),
min(length(unique(sce_viz$image_fullname)), nb_images)))
# Folders
folder_images <- file.path(paths$folder_in, "img", paths$panel_type)
folder_masks <- file.path(paths$folder_in, "masks_cells",
paths$panel_type, "whole-cell")
# Load images and masks
images <- imgloader(
x = sce_viz,
image_dir = folder_images,
image_names = image_sub,
type = "stacks"
)
masks <- imgloader(
x = sce_viz,
image_dir = folder_masks,
image_names = image_sub,
as.is = TRUE,
type = "masks"
)
sce_viz <- sce_viz[, sce_viz$image_fullname %in% image_sub]
sce_viz$ImageName <- gsub(image_extension, "", sce_viz$image_fullname)
}
Loading required package: cytomapper
Loading required package: EBImage
Attaching package: 'EBImage'
The following object is masked from 'package:plotly':
toRGB
The following object is masked from 'package:purrr':
transpose
The following object is masked from 'package:data.table':
transpose
The following object is masked from 'package:SummarizedExperiment':
resize
The following object is masked from 'package:Biobase':
channel
The following objects are masked from 'package:GenomicRanges':
resize, tile
The following objects are masked from 'package:IRanges':
resize, tile
Attaching package: 'cytomapper'
The following objects are masked from 'package:Biobase':
channelNames, channelNames<-
[1] "Loading image stacks"
# Use cytoviewer with images, masks and object
library(cytoviewer)
if (!is.null(viz_clust)) {
channels_view <- channels_clust
sub_images <- cytomapper::getChannels(images, channels_view)
app <- cytoviewer(image = sub_images,
mask = masks,
object = sce_viz[channels_view, ],
img_id = "ImageName",
cell_id = "cell_number")
#if (interactive()) {
# shiny::runApp(app)
#}
}
Note: this section requires manual intervention
Here, clusters obtained at the previous steps are manually merged into meaningful cell categories. Cluster numbers are attributed to the different cell categories based on the plots and heatmaps above. Consequently, this attribution has to be adapted to the clustering results.
clust_methods <- c("Pheno1")
clust_assay <- c("scaled")
if (!clust_assay %in% assay_sel) stop("The selected assay is not in the assays selected for clustering")
if (length(clust_assay) != 1) stop("Select only one assay")
clust_name <- paste(clust_methods, clust_assay, "cat", sep = "_")
print(clust_name)
[1] "Pheno1_scaled_cat"
# Define which clusters correspond to which cell types
# Islet: 16:19, 10
# Exocrine: 26, 22, 23, 11, 20, 8, 6, 21
# Other: 2, 3, 13, 10, 1, 5
# Stroma: 13, 4, 25
# Immune: 7, 12, 15, 24, 27, 14
# 9
clust_other <- c(2, 3, 1, 5)
clust_islet <- c(16:19, 10)
clust_immune <- c(7, 12, 15, 24, 27, 14, 9)
clust_stroma <- c(13, 4, 25)
clust_exocrine <- c(26, 22, 23, 11, 20, 8, 6, 21)
all_clust <- sort(c(clust_islet, clust_immune, clust_exocrine, clust_stroma,clust_other))
if ((!length(unique(all_clust)) ==
length(unique(colData(sce_cat)[, clust_name]))) ||
any(duplicated(all_clust))) {
stop("Recheck cluster attribution")
}
# Add cell types to the SCE object
# Islet
colData(sce_cat)[colData(sce_cat)[, clust_name] %in% clust_islet,
"CellCat"] <- "Islet"
colData(sce_cat)[colData(sce_cat)[, clust_name] %in% clust_immune,
"CellCat"] <- "Immune"
colData(sce_cat)[colData(sce_cat)[, clust_name] %in% clust_exocrine,
"CellCat"] <- "Exocrine"
colData(sce_cat)[colData(sce_cat)[, clust_name] %in% clust_stroma,
"CellCat"] <- "Stroma"
colData(sce_cat)[colData(sce_cat)[, clust_name] %in% clust_other,
"CellCat"]<- "Other"
sce_sub_cat$Pheno1_scaled_cat <- sce_cat[, metadata(spe)[["subset"]]]$Pheno1_scaled_cat
sce_sub_cat$CellCat <- sce_cat[, metadata(spe)[["subset"]]]$CellCat
# Prepare the data
cur_dat <- makePerCellDF(sce_sub_cat, use_dimred = TRUE) |>
mutate(case_id = factor(case_id, levels = metadata(sce_sub_cat)$cases),
donor_type = factor(donor_type, levels = metadata(sce_sub_cat)$stages)) |>
arrange(case_id, donor_type)
# Plot
cur_assay <- "scaled"
cur_dimred <- "UMAP"
cur_method <- "Pheno1"
dimred_name <- paste(cur_dimred, cur_assay, "cat", sep = "_")
clust_name <- "CellCat"
p <- plot_dim_red(cur_dat, dimred_name, clust_name,
sample = TRUE, size = 1, alpha = 1)
print(p)
fn <- paste0(paste(today, clust_name, cur_dimred,
sep = "_"), ".png")
do.call(ggsave, c(list(fn, p), plotsave_param))
name_cur_assay <- "scaled"
# Summarize the data
hm <- summarize_heatmap(sce_cat,
expr_values = name_cur_assay,
cluster_by = clust_name,
channels = channels_cat)
# Display the heatmap
fn <- paste0(paste(today, clust_name, "Heatmap",
sep = "_"), ".html")
heatmaply(
heatmaply::normalize(hm), main = clust_name,
file = file.path(paths$folder_script, fn))
table(colData(sce_cat)[, "CellCat"])
Exocrine Immune Islet Other Stroma
48448 12653 20999 47091 10438
sce_cat <- sce_cat[, colnames(spe)]
spe$cell_category <- colData(sce_cat)$CellCat
table(spe$cell_category)
Exocrine Immune Islet Other Stroma
48448 12653 20999 47091 10438
fn_spe <- file.path(paths$folder_out, paste0(paths$object_type, "_", paths$panel_type, ".rds"))
print(spe)
class: SpatialExperiment
dim: 27 139629
metadata(2): spillover_matrix subset
assays(6): counts compcounts ... scaled fastMNN_case_id
rownames(27): H3 CD44_GCG ... DNA3 PPY
rowData names(10): channel metal ... shortname channel_name
colnames(139629): 6238_Compressed_001_1 6238_Compressed_001_2 ...
6396_Compressed_030_1445 6396_Compressed_030_1446
colData names(32): case_id panel ... Pheno1_scaled_cat cell_category
reducedDimNames(0):
mainExpName: NULL
altExpNames(0):
spatialCoords names(2) : cell_x cell_y
imgData names(1): sample_id
saveRDS(spe, fn_spe)
sessionInfo()
R version 4.3.1 (2023-06-16)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 20.04.6 LTS
Matrix products: default
BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.9.0
locale:
[1] LC_CTYPE=C.UTF-8 LC_NUMERIC=C LC_TIME=C.UTF-8
[4] LC_COLLATE=C.UTF-8 LC_MONETARY=C.UTF-8 LC_MESSAGES=C.UTF-8
[7] LC_PAPER=C.UTF-8 LC_NAME=C LC_ADDRESS=C
[10] LC_TELEPHONE=C LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C
time zone: Etc/UTC
tzcode source: system (glibc)
attached base packages:
[1] parallel stats4 stats graphics grDevices utils datasets
[8] methods base
other attached packages:
[1] cytoviewer_1.2.0 cytomapper_1.14.0
[3] EBImage_4.44.0 htmltools_0.5.8.1
[5] heatmaply_1.5.0 viridis_0.6.5
[7] viridisLite_0.4.2 plotly_4.10.4
[9] BiocParallel_1.36.0 patchwork_1.2.0
[11] Rphenoannoy_0.1.0 Matrix_1.6-5
[13] igraph_2.1.4 scran_1.30.2
[15] scater_1.30.1 scuttle_1.12.0
[17] furrr_0.3.1 future_1.49.0
[19] purrr_1.0.2 data.table_1.17.2
[21] SpatialExperiment_1.12.0 SingleCellExperiment_1.24.0
[23] SummarizedExperiment_1.32.0 Biobase_2.62.0
[25] GenomicRanges_1.54.1 GenomeInfoDb_1.38.8
[27] IRanges_2.36.0 S4Vectors_0.40.2
[29] BiocGenerics_0.48.1 MatrixGenerics_1.14.0
[31] matrixStats_1.5.0 dplyr_1.1.4
[33] ggplot2_3.5.1
loaded via a namespace (and not attached):
[1] RcppAnnoy_0.0.22 later_1.3.2
[3] bitops_1.0-9 svgPanZoom_0.3.4
[5] tibble_3.2.1 lifecycle_1.0.4
[7] edgeR_4.0.16 rprojroot_2.0.4
[9] globals_0.18.0 lattice_0.22-7
[11] crosstalk_1.2.1 dendextend_1.17.1
[13] magrittr_2.0.3 limma_3.58.1
[15] sass_0.4.9 rmarkdown_2.27
[17] jquerylib_0.1.4 yaml_2.3.10
[19] metapod_1.10.1 httpuv_1.6.15
[21] sp_2.1-4 RColorBrewer_1.1-3
[23] abind_1.4-8 zlibbioc_1.48.2
[25] RCurl_1.98-1.14 git2r_0.33.0
[27] seriation_1.5.5 GenomeInfoDbData_1.2.11
[29] ggrepel_0.9.5 irlba_2.3.5.1
[31] listenv_0.9.1 terra_1.7-78
[33] dqrng_0.4.1 parallelly_1.44.0
[35] svglite_2.1.3 DelayedMatrixStats_1.24.0
[37] codetools_0.2-20 DelayedArray_0.28.0
[39] tidyselect_1.2.1 raster_3.6-26
[41] farver_2.1.2 ScaledMatrix_1.10.0
[43] TSP_1.2-4 webshot_0.5.5
[45] jsonlite_2.0.0 BiocNeighbors_1.20.2
[47] iterators_1.0.14 systemfonts_1.1.0
[49] foreach_1.5.2 tools_4.3.1
[51] ragg_1.3.2 Rcpp_1.0.14
[53] glue_1.8.0 gridExtra_2.3
[55] SparseArray_1.2.4 xfun_0.52
[57] ca_0.71.1 HDF5Array_1.30.1
[59] shinydashboard_0.7.2 withr_3.0.2
[61] fastmap_1.2.0 rhdf5filters_1.14.1
[63] bluster_1.12.0 fansi_1.0.6
[65] digest_0.6.37 rsvd_1.0.5
[67] R6_2.6.1 mime_0.13
[69] textshaping_0.4.0 colorspace_2.1-1
[71] jpeg_0.1-11 utf8_1.2.5
[73] tidyr_1.3.1 generics_0.1.4
[75] httr_1.4.7 htmlwidgets_1.6.4
[77] S4Arrays_1.2.1 whisker_0.4.1
[79] uwot_0.2.2 pkgconfig_2.0.3
[81] gtable_0.3.6 registry_0.5-1
[83] workflowr_1.7.1 XVector_0.42.0
[85] fftwtools_0.9-11 scales_1.3.0
[87] png_0.1-8 knitr_1.47
[89] reshape2_1.4.4 rjson_0.2.23
[91] rhdf5_2.46.1 cachem_1.1.0
[93] stringr_1.5.1 shinycssloaders_1.0.0
[95] miniUI_0.1.1.1 vipor_0.4.7
[97] pillar_1.9.0 grid_4.3.1
[99] vctrs_0.6.5 RANN_2.6.2
[101] promises_1.3.0 BiocSingular_1.18.0
[103] beachmat_2.18.1 xtable_1.8-4
[105] cluster_2.1.8.1 archive_1.1.12
[107] beeswarm_0.4.0 evaluate_1.0.3
[109] magick_2.8.3 cli_3.6.5
[111] locfit_1.5-9.9 compiler_4.3.1
[113] rlang_1.1.6 crayon_1.5.3
[115] labeling_0.4.3 plyr_1.8.9
[117] fs_1.6.6 ggbeeswarm_0.7.2
[119] stringi_1.8.7 nnls_1.6
[121] assertthat_0.2.1 munsell_0.5.1
[123] lazyeval_0.2.2 tiff_0.1-12
[125] colourpicker_1.3.0 sparseMatrixStats_1.14.0
[127] Rhdf5lib_1.24.2 statmod_1.5.0
[129] shiny_1.8.1.1 highr_0.11
[131] fontawesome_0.5.3 memoise_2.0.1
[133] bslib_0.7.0